﻿using HK.Core.Network.Download.Protocol.Data;
using HK.Core.Threader.Protocol;

namespace HK.Core.Network.Download.Protocol.Control
{

    /// <summary>
    /// 下载器状态
    /// </summary>
    public enum DownloadState
    {
        /// <summary>
        /// 无
        /// <para>* 尚未初始化之前的状态</para>
        /// </summary>
        None = -1,
        /// <summary>
        /// 正常
        /// </summary>
        Ok = 0,
        /// <summary>
        /// 已取消
        /// </summary>
        Canceled = 1,
        /// <summary>
        /// 失败
        /// </summary>
        Failed = 2,
        /// <summary>
        /// 异常
        /// </summary>
        Exception = 3,
        /// <summary>
        /// 网络异常
        /// </summary>
        WebException = 4,
        /// <summary>
        /// 文件大小不匹配(单位L:Byte)
        /// </summary>
        FileSizeNotMatch = 5,
        /// <summary>
        /// 校验码不匹配
        /// </summary>
        CheckCodeNotMatch = 6,
        /// <summary>
        /// 解密/解压失败
        /// </summary>
        DecompressedFailed = 7,
        /// <summary>
        /// 移动文件失败
        /// </summary>
        MoveFileFailed = 8,
        /// <summary>
        /// 网络错误
        /// </summary>
        NetworkErr = 9
    }
    
    /// <summary>
    /// 下载选项
    /// </summary>
    public enum DownloadOptions
    {
        /// <summary>
        /// 无
        /// </summary>
        None = 0x00000000,
        
        /// <summary>
        /// 开启线程下载
        /// </summary>
        UseThread = 0x00000001,
        
        /// <summary>
        /// 重试
        /// </summary>
        Retry = 0x00000002,
        
        /// <summary>
        /// 文件大小校验
        /// </summary>
        SizeCheck = 0x00000004,
        
        /// <summary>
        /// 目标目录存在校验
        /// <para>* 若目标目录不存在，则自动创建</para>
        /// </summary>
        DstDirExistCheck = 0x00000010,
        
        /// <summary>
        /// 校验 - Crc
        /// </summary>
        CrcCheck = 0x0000020,
        
        /// <summary>
        /// 校验 - Md5
        /// </summary>
        Md5Check = 0x00000040,
        
        /// <summary>
        /// 解压/解密
        /// </summary>
        Decompressed = 0x00000080,
        
        /// <summary>
        /// 一般下载
        /// </summary>
        GenericDownload = Retry | SizeCheck | DstDirExistCheck,
        
        /// <summary>
        /// 资源下载
        /// <para>* 包含：</para>
        /// <para> 1) 文件大小</para>
        /// <para> 2) Crc校验</para>
        /// </summary>
        ResDownload = UseThread | Retry | SizeCheck | CrcCheck | DstDirExistCheck,
        
        /// <summary>
        /// 资源下载
        /// <para>* 包含：</para>
        /// <para> 1) 文件大小</para>
        /// <para> 2) Crc校验</para>
        /// <para> 3) 解压缩:(默认:Jab)</para>
        /// </summary>
        ResFullDownload = UseThread | Retry | SizeCheck | CrcCheck | DstDirExistCheck | Decompressed,
        
        /// <summary>
        /// 资源下载
        /// <para>* 包含：</para>
        /// <para> 1) 文件大小</para>
        /// <para> 2) Md5校验</para>
        /// <para> 3) 解压缩:(默认:Jab)</para>
        /// </summary>
        ResMd5Download = UseThread | Retry | SizeCheck | Md5Check | DstDirExistCheck | Decompressed
    }

    /// <summary>
    /// 解压/解密方式
    /// </summary>
    public enum DecodeType
    {
        /// <summary>
        /// 解压/解密
        /// </summary>
        Jab
    }
    
    /// <summary>
    /// 事件委托定义 : 下载器执行完成回调
    /// <para>* 单个下载目标完成回调.（包括成功与失败）</para>
    /// <param name="iState">下载状态</param>
    /// <param name="iDownloader">下载器</param>
    /// <param name="iMessage">消息的具体内容</param>
    /// </summary>
    /// <returns>null:没有下一个需要下载的信息; 其他:下一个需要下载的目标信息;</returns>
    public delegate IDownloadInfo DownloaderCompleted(DownloadState iState, IDownloader iDownloader, string iMessage = null);

    /// <summary>
    /// 事件委托定义 : 解压机密
    /// <para>* 支持外部回调的方式解密/解压，但是必须要保证外部调用线程安全。</para>
    /// </summary>
    public delegate bool DownloadDecompressed(IDownloadInfo iTarget);
    
    /// <summary>
    /// 接口 : 下载器
    /// </summary>
    public interface IDownloader : IThreader
    {
        
        /// <summary>
        /// 索引
        /// </summary>
        int Index { get; }

#region State

        /// <summary>
        /// 状态
        /// </summary>
        DownloadState State { get; }
        
        /// <summary>
        /// 状态描述
        /// </summary>
        string StateDesc { get; }

#endregion

#region Options

        /// <summary>
        /// 校验选项
        /// </summary>
        int Options { get; }
        
        /// <summary>
        /// 开启线程下载
        /// </summary>
        bool UseThread { get; }

        /// <summary>
        /// 重试标志位
        /// </summary>
        bool Retry { get; }
        
        /// <summary>
        /// 重试上限数
        /// </summary>
        int RetryMaxNum { get; }
        
        /// <summary>
        /// 重试数
        /// </summary>
        int RetryCount { get; }
        
        /// <summary>
        /// 文件大小校验
        /// </summary>
        bool SizeCheck { get; }
        
        /// <summary>
        /// 目标目录存在校验
        /// <para>* 若目标目录不存在，则自动创建</para>
        /// </summary>
        bool DstDirExistCheck { get; }

        /// <summary>
        /// 校验标志位 - Crc
        /// </summary>
        bool CrcCheck { get; }

        /// <summary>
        /// 校验标志位 - Md5
        /// </summary>
        bool Md5Check { get; }
        
        /// <summary>
        /// 解压/解密
        /// </summary>
        bool Decompressed { get; }
        
        /// <summary>
        /// 缓存大小
        /// <para>* 下载时单次写入的缓存大小。单位:Byte。默认:2048</para>
        /// </summary>
        int BufferSize { get; }
        
        /// <summary>
        /// 下载超时
        /// <para>* 单位 : 秒。默认：30秒</para>
        /// </summary>
        int TimeOut { get; }
        
        /// <summary>
        /// 移动文件标志位
        /// <para>* true:下载完毕，将文件从临时下载目录移动到目标目录;</para>
        /// </summary>
        bool MoveFile { get; }
        
        /// <summary>
        /// 解压/解密方式
        /// </summary>
        DecodeType Decode { get; }

#endregion

#region Info

        /// <summary>
        /// 下载目标信息
        /// </summary>
        IDownloadInfo Target { get; }
        
        /// <summary>
        /// 下载Url
        /// </summary>
        string DownloadUrl { get; }
        
        /// <summary>
        /// 已下载完成的大小
        /// <para>* 单位 : Byte</para>
        /// </summary>
        long DownloadedSize { get; }
        
        /// <summary>
        /// 总共大小
        /// <para>* 单位 : Byte</para>
        /// </summary>
        long TotalSize { get; }
        
        /// <summary>
        /// 文件名
        /// </summary>
        string FileName { get; }
        
        /// <summary>
        /// 下载保存路径
        /// <para>* 该路径为，下载临时保存路径。下载成功并通过文件校验后，将拷贝到真正的保存路径。即:SavePath</para>
        /// </summary>
        string DownloadPath { get; }
        
        /// <summary>
        /// 保存路径
        /// </summary>
        string SavePath { get; }
        
        /// <summary>
        /// 校验码 - Crc
        /// </summary>
        long CrcCheckCode { get; }
        
        /// <summary>
        /// 校验码 - Md5
        /// </summary>
        string Md5CheckCode { get; }

#endregion
        
#region Events

        /// <summary>
        /// 完成回调
        /// </summary>
        DownloaderCompleted Completed { get; }
        
        /// <summary>
        /// 解压/解密回调
        /// </summary>
        DownloadDecompressed DoDecompressed { get; }

#endregion

#region Download

        /// <summary>
        /// 开始下载
        /// </summary>
        /// <param name="iTarget">下载目标信息</param>
        /// <returns>true:OK; false:Ng;</returns>
        bool Start(IDownloadInfo iTarget);

#endregion

    }
}
